/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/05/29
* File: enn_work_queue.h
* Blog: http://www.cnblogs.com/zengqh/
**/

#pragma once

#include "enn_thread.h"

namespace enn
{
class WorkerThread;

/// Work queue item.
struct WorkItem
{
	// Construct
	WorkItem() :
	priority_(ENN_MAX_UNSIGNED),
	sendEvent_(false),
	completed_(false)
	{

	}

	/// Work function. Called with the work item and thread index (0 = main thread) as parameters.
	void (*workFunction_)(const WorkItem*, unsigned);
	/// Data start pointer.
	void* start_;
	/// Data end pointer.
	void* end_;
	/// Auxiliary data pointer.
	void* aux_;
	/// Priority. Higher value = will be completed first.
	unsigned priority_;
	/// Whether to send event on completion.
	bool sendEvent_;
	/// Completed flag.
	volatile bool completed_;
};

/// Work queue subsystem for multithreading.
class WorkQueue : public Noncopyable, public AllocatedObject
{
	friend class WorkerThread;

public:
	/// Construct.
	WorkQueue();
	/// Destruct.
	~WorkQueue();

	/// Create worker threads. Can only be called once.
	void CreateThreads(unsigned numThreads);
	/// Add a work item and resume worker threads.
	void AddWorkItem(const WorkItem& item);
	/// Pause worker threads.
	void Pause();
	/// Resume worker threads.
	void Resume();
	/// Finish all queued work which has at least the specified priority. Main thread will also execute priority work. Pause worker threads if no more work remains.
	void Complete(unsigned priority);

	/// Return number of worker threads.
	unsigned GetNumThreads() const { return threads_.Size(); }
	/// Return whether all work with at least the specified priority is finished.
	bool IsCompleted(unsigned priority) const;

private:
	/// Process work items until shut down. Called by the worker threads.
	void ProcessItems(unsigned threadIndex);
	/// Purge completed work items and send completion events as necessary.
	void PurgeCompleted();

	/// Worker threads.
	enn::vector<WorkerThread*>::type threads_;
	/// Work item collection. Accessed only by the main thread.
	enn::list<WorkItem>::type workItems_;
	/// Work item prioritized queue for worker threads. Pointers are guaranteed to be valid (point to workItems.)
	enn::list<WorkItem*>::type queue_;
	/// Worker queue mutex.
	Mutex queueMutex_;
	/// Shutting down flag.
	volatile bool shutDown_;
	/// Pausing flag. Indicates the worker threads should not contend for the queue mutex.
	volatile bool pausing_;
	/// Paused flag. Indicates the queue mutex being locked to prevent worker threads using up CPU time.
	bool paused_;
};

}